#pragma once

#include <iostream>
#include <string>
#include <string>
#include <queue>
#include <vector>
#include <memory>
#include "log.hpp"
#include "Mutex.hpp"
#include "thread.hpp"
#include "Cond.hpp"

namespace threadPoolModule
{
    using namespace logModule;
    using namespace threadModule;
    using namespace mutexModule;
    using namespace condModule;

    // zdl:: 用来做测试的线程函数方法
    void defaultTest()
    {
        while (true)
        {
            LOG(logLevel::debug) << "这是一个测试方法";
            sleep(1);
        }
    }

    const static int defaultnum = 5;

    // template <class t>
    using thread_t = std::shared_ptr<Thread>;

    template <class t>
    class threadPool
    {
    private:
        bool isEmpty() { return _taskq.empty(); }
        void handlerTask(const std::string &name)
        {
            LOG(logLevel::info) << "thread - " << name << " handlerTask lauched";
            while (true)
            {
                t task;
                // 1.拿任务 // zdl:: 在进行处理任务的时候不需要加锁
                {
                    LockGuard lockguard(_lock);
                    while (isEmpty() && _isRunning)
                    {
                        _wait_num++;
                        _cond.wait(_lock);
                        _wait_num--;
                    }
                    if (isEmpty() && !_isRunning)
                        break;
                        // 2. 任务队列不为空 && 线程池退出
                    task = _taskq.front();
                    _taskq.pop();
                }
                // 2.处理任务
                task(name); // 规定所有的任务处理都必须提供()处理
            }
            LOG(logLevel::info) << "线程" << name << "退出";
        }

    public:
        threadPool(int num = defaultnum) : _num(num), _wait_num(num), _isRunning(false)
        {
            for (int i = 0; i < _num; i++)
            {
                _threads.emplace_back(std::make_shared<Thread>(std::bind(&threadPool::handlerTask, this,
                                                                        std::placeholders::_1)));
                LOG(logLevel::info) << "构建线程" << _threads.back()->getName() << "对象成功";
            }
        };
        ~threadPool()
        {
        }

        void start()
        {
            // 避免重复的启动
            if (_isRunning)
                return;

            _isRunning = true;
            for (auto &p : _threads)
            {
                LOG(logLevel::info) << "启动线程" << p->getName() << "。。。成功";
                p->Running();
            }
        }
        void equeue(t in)
        {
            if (!_isRunning)
                return;
            LockGuard lockguard(_lock);
            _taskq.push(std::move(in));
            if (_wait_num > 0)
            {
                _cond.notify();
            }
        }
        void stop()
        {
            LockGuard lockguard(_lock);
            if (_isRunning)
            {
                _isRunning = false;
                // 1. 让线程自己退出(要唤醒) && 历史任务都处理完
                if (_wait_num > 0)
                    _cond.notifyAll();
                // 2， 历史的任务被处理完
                // 3. 不能再入队伍
            }
        }
        void wait()
        {
            for (auto &p : _threads)
            {
                p->join();
                LOG(logLevel::info) << "回收线程" << p->getName() << "。。。成功";
            }
        }

    private:
        int _num;
        std::queue<t> _taskq; // 临界资源
        std::vector<thread_t> _threads;
        int _wait_num;

        Mutex _lock;
        Cond _cond;
        bool _isRunning;
    };
}
